home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 016a / gofer221.zip / MATRIX < prev    next >
Text File  |  1991-11-20  |  4KB  |  93 lines

  1. -- Some simple Gofer programs for manipulating matrices.
  2. --
  3.  
  4. type Matrix k = [Row k]          -- matrix represented by a list of its rows
  5. type Row k    = [k]              -- a row represented by a list of literals
  6.  
  7. -- General utility functions:
  8.  
  9. shapeMat    :: Matrix k -> (Int, Int)
  10. shapeMat mat = (rows mat, cols mat)
  11.  
  12. rows        :: Matrix k -> Int
  13. rows mat     = length mat
  14.  
  15. cols        :: Matrix k -> Int
  16. cols mat     = length (head mat)
  17.  
  18. idMat       :: Int -> Matrix Int
  19. idMat 0      = []
  20. idMat (n+1)  = [1:copy n 0] ++ map (0:) (idMat n)
  21.  
  22. -- Matrix multiplication:
  23.  
  24. multiplyMat                     :: Matrix Int -> Matrix Int -> Matrix Int
  25. multiplyMat a b | cols a==rows b = [[row `dot` col | col<-b'] | row<-a]
  26.                 | otherwise      = error "incompatible matrices"
  27.                  where v `dot` w = sum (zipWith (*) v w)
  28.                        b'        = transpose b
  29.  
  30. -- An attempt to implement the standard algorithm for converting a matrix
  31. -- to echelon form...
  32.  
  33. echelon   :: Matrix Int -> Matrix Int
  34. echelon rs = rs,                                if null rs || null (head rs)
  35.            = map (0:) (echelon (map tail rs)),  if null rs2
  36.            = piv : map (0:) (echelon rs'),      otherwise
  37.              where rs'            = map (adjust piv) (rs1++rs3)
  38.                    (rs1,rs2)      = span leadZero rs
  39.                    leadZero (n:_) = n==0
  40.                    (piv:rs3)      = rs2
  41.  
  42. -- To find the echelon form of a matrix represented by a list of rows rs:
  43. -- 
  44. -- {first line in definition of echelon}:
  45. --  If either the number of rows or the number of columns in the matrix
  46. --  is zero (i.e. if null rs || null (head rs)), then the matrix is
  47. --  already in echelon form.
  48. -- 
  49. -- {definition of rs1, rs2, leadZero in where clause}:
  50. --  Otherwise, split the matrix into two submatrices rs1 and rs2 such that
  51. --  rs1 ++ rs2 == rs  and all of the rows in rs1 begin with a zero.
  52. --
  53. -- {second line in definition of echelon}:
  54. --  If rs2 is empty (i.e. if null rs2) then every row begins with a zero
  55. --  and the echelon form of rs can be found by adding a zero on to the
  56. --  front of each row in the echelon form of (map tail rs).
  57. --
  58. -- {Third line in definition of echelon, and definition of piv, rs3}:
  59. --  Otherwise, the first row of rs2 (denoted piv) contains a non-zero
  60. --  leading coefficient.  After moving this row to the top of the matrix
  61. --  the original matrix becomes  piv:(rs1++rs3).
  62. --  By subtracting suitable multiples of piv from (suitable multiples of)
  63. --  each row in (rs1++rs3) {see definition of adjust below}, we obtain a
  64. --  matrix of the form:
  65. --
  66. --          <----- piv ------>
  67. --          __________________
  68. --          0  |
  69. --          .  |
  70. --          .  |      rs'        where rs' = map (adjust piv) (rs1++rs3)
  71. --          .  |
  72. --          0  |
  73. --
  74. --  whose echelon form is  piv : map (0:) (echelon rs').
  75. --
  76.  
  77. adjust              :: Num a => Row a -> Row a -> Row a
  78. adjust (m:ms) (n:ns) = zipWith (-) (map (n*) ms) (map (m*) ns)
  79.  
  80. -- A more specialised version of this, for matrices of integers, uses the
  81. -- greatest common divisor function gcd in an attempt to try and avoid
  82. -- result matrices with very large coefficients:
  83. --
  84. -- (I'm not sure this is really worth the trouble!)
  85.  
  86. adjust'              :: Row Int -> Row Int -> Row Int
  87. adjust' (m:ms) (n:ns) = ns,                                  if g==0
  88.                       = zipWith (\x y -> b*y - a*x) ms ns,   otherwise
  89.                         where g = gcd m n
  90.                               a = n/g
  91.                               b = m/g
  92. -- end!!
  93.